// These functions provide access to low-level allocation of memory from the operating system.

typedef struct runtime_Mem_Area {
	void *area_start;
	uintptr total_pages;
} runtime_Mem_Area;

// Translates a page number in an area to a virtual address (pointer to the beginning of the page). 
static inline void *
runtime_sys_page_addr(struct runtime_Mem_Area *area, uintptr page) {
	return ((char *)(area->area_start)) + page * PAGE_SIZE;
}

static inline uintptr
runtime_sys_page_id(struct runtime_Mem_Area *area, void *ptr) {
	return ((uintptr)ptr - (uintptr)(area->area_start)) / PAGE_SIZE;
}

static inline bool
runtime_sys_contains(struct runtime_Mem_Area *area, void *ptr) {
	return (uintptr)ptr >= (uintptr)area->area_start && (uintptr)ptr < (uintptr)area->area_start + area->total_pages * PAGE_SIZE;
}

static inline uintptr
runtime_sys_pages(struct runtime_Mem_Area *area) {
	return area->total_pages;
}

// Asks the system to create an area of virtual memory starting at prefer_start_page and
// spanning as many pages as requested. Both values are multiplied by PAGE_SIZE to get an exact
// address/size in bytes. If the area can't be created, the return value is false and the
// structure pointed to by area is unchanged.
// The implementation is allowed to not actually allocate any memory.
// It can allocate just part of the virtual address space.
bool runtime_sys_create(struct runtime_Mem_Area *area, uintptr prefer_start_page, uintptr pages);

// Completely frees an area. The structure can then be reused.
// No memory in this area must be used if this function is called.
void runtime_sys_destroy(struct runtime_Mem_Area *area);

// Asks the system to resize a virtual memory area to a requested number of pages. Can fail. 
bool runtime_sys_resize(struct runtime_Mem_Area *area, uintptr pages);

// Tells the operating system that some pages from a previously created area are about to be used.
// No part of the area can be used (read from or written to), before claim is called on it.
// This operation can fail if there is not enough physical memory available.
// start_page is relative to the beginning of the area and starts at 0.
// Can be a no-op.
bool runtime_sys_claim(struct runtime_Mem_Area *area, uintptr start_page, uintptr pages);

// Tells the operating system that some pages from a previously created area are no longer in use
// and may be unmapped and recycled.
// The said pages must not be read or written after release is called, until claim is called again.
// Can be a no-op (in which case no memory is ever released back to the operating system).
void runtime_sys_release(struct runtime_Mem_Area *area, uintptr start_page, uintptr pages);



// Allocates a chunk of memory directly from the operating system.
void *runtime_sys_alloc(uintptr size);

// Frees a chunk of memory allocated by runtime_sys_alloc().
void runtime_sys_free(void *m);
